//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Microsoft.Research.ScientificWorkflow.TridentModel;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using System.Windows.Data;

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    /// <summary>
    /// Interaction logic for RunWindow.xaml
    /// </summary>
    public partial class RunWindow : Window
    {
        #region Private fields
        /// <summary>
        /// The job details.
        /// </summary>
        private JobDetailModel jobDetail;

        /// <summary>
        /// The parameters to be shown to the user.
        /// </summary>
        private Collection<ParameterDescriptionModel> parameterList = new Collection<ParameterDescriptionModel>();

        /// <summary>
        /// A dictionary containing the original as the key and its clone as the value.
        /// </summary>
        private Dictionary<ParameterDescriptionModel, ParameterDescriptionModel> parameterCloneDictionary =
            new Dictionary<ParameterDescriptionModel, ParameterDescriptionModel>();

        /// <summary>
        /// Additional parameters.
        /// </summary>
        private ObservableCollection<AdditionalParametersModel> additionalParameters = new ObservableCollection<AdditionalParametersModel>();
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the run window.
        /// </summary>
        /// <param name="parameters">The parameters to be shown to the user.</param>
        /// <param name="outputParameters">The output parameters to be shown to the user.</param>
        /// <param name="jobDetails">The job details.</param>
        public RunWindow(
            Collection<ParameterDescriptionModel> parameters,
            Collection<ParameterDescriptionModel> outputParameters,
            JobDetailModel jobDetails)
        {
            InitializeComponent();
            this.brdrHeader.MouseLeftButtonDown += (sender, e) => this.DragMove();

            // Create a copy of the param description model and add to the list. Copy is needed because the user can cancel the run.
            foreach (ParameterDescriptionModel originalModel in parameters)
            {
                ParameterDescriptionModel copy = new ParameterDescriptionModel(originalModel);
                this.parameterList.Add(copy);
                this.parameterCloneDictionary.Add(originalModel, copy);
            }

            this.jobDetail = jobDetails;
            this.propertyListControl.CurrentValidationMode = ValidationMode.All;
            this.propertyListControl.UpdateList(parameterList);

            this.outputPropertyListControl.CurrentControlMode = ControlMode.ReadOnly;
            this.outputPropertyListControl.UpdateList(outputParameters);

            this.additionalParametersGrid.ItemsSource = this.additionalParameters;
            this.TitleTextBlock.Text = jobDetail.WorkflowName + TridentResourceManager.GetString("RunWindowTitle");
        }
        #endregion

        #region public properties
        /// <summary>
        /// Gets the flag which determines whether the user has clicked on cancel or close button.
        /// </summary>
        public bool CancelClicked { get; private set; }
        #endregion

        #region Private methods
        /// <summary>
        /// Event handler for the window mouse down event. Used in drag of the window.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }

        /// <summary>
        /// Event handler for the add additional parameter button click.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            this.additionalParameters.Add(new AdditionalParametersModel());
        }

        /// <summary>
        /// Event handler for the delete additional parameter button click.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.additionalParametersGrid.SelectedItem != null)
            {
                this.additionalParameters.Remove(this.additionalParametersGrid.SelectedItem as AdditionalParametersModel);
            }
        }

        /// <summary>
        /// Event handler for the create job button click.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void ExecuteButton_Click(object sender, RoutedEventArgs e)
        {
            // Check if all parameters have been filled with valid values.
            if (!this.propertyListControl.PropertiesValid)
            {
                this.ErrorMessageText.Text = TridentResourceManager.GetString("RunWindowParametersInvalid");
                this.ErrorMessageText.Visibility = Visibility.Visible;
                return;
            }

            // Validate the additional parameters.
            if (!CheckIfAdditionalParametersValid())
            {
                this.ErrorMessageText.Text = TridentResourceManager.GetString("AdditionalParameterError");
                this.ErrorMessageText.Visibility = Visibility.Visible;
                return;
            }

            this.ErrorMessageText.Visibility = Visibility.Hidden;

            this.jobDetail.Notes = notesTextBox.Text;
            this.jobDetail.IsDebug = isDebug.IsChecked.Value;

            foreach (AdditionalParametersModel additionalParameter in this.additionalParameters)
            {
                jobDetail.AdditionalParameters.Add(additionalParameter);
            }

            // Apply the values in the cloned models to the original models.
            foreach (ParameterDescriptionModel key in this.parameterCloneDictionary.Keys)
            {
                ParameterDescriptionModel copy = this.parameterCloneDictionary[key];
                key.Value = copy.Value;
            }
            this.Close();
        }

        /// <summary>
        /// Event handler for the cancel/close button click.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.CancelClicked = true;
            this.Close();
        }

        /// <summary>
        /// Check if additional parameters have valid values.
        /// </summary>
        /// <returns>True if all additional parameters have valid values. False otherwise.</returns>
        private bool CheckIfAdditionalParametersValid()
        {
            AdditionalParametersModel invalidModel = this.additionalParameters.FirstOrDefault(p => (string.IsNullOrEmpty(p.Parameter) || string.IsNullOrEmpty(p.ParameterValue)));
            return invalidModel == null ? true : false;
        }
        #endregion
    }

    public class DeleteEnabledConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members

        public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool itemsPresent = (bool)values[0];
            object selectedItem = values[1];
            if (itemsPresent == true && selectedItem != null)
            {
                return true;
            }
            return false;
        }

        public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            return new object[] { };
        }

        #endregion
    }

}
